<?php
// +-------------------------------------------------------------------------------
// | DingZone [ A Rapid Development Framework For Dingtalk ]
// +-------------------------------------------------------------------------------
// | CacheKey.php v1.0
// |
// | Copyright (c) 2014-2018 http://www.heimalanshi.com All rights reserved.
// | Author : Jie
// | Date : 2018-08-12
// +-------------------------------------------------------------------------------


namespace app\core\model;


use think\Cache;
use think\Db;

class CacheKey {
    private $moduleName;
    private $resourceType;
    private $tags;
    private $expire;

    /**
     * @param string|\think\Request $moduleName
     * @return CacheKey
     */
    public static function module($moduleName = null) {
        $cacheKey = new self();
        $cacheKey->moduleName = $moduleName ? $moduleName : request()->module();
        return $cacheKey;
    }

    /**
     * @param mixed $resourceType
     * @return CacheKey
     */
    public function type($resourceType) {
        $this->resourceType = $resourceType;
        return $this;
    }

    /**
     * @param mixed $tags
     * @return CacheKey
     */
    public function tags($tags) {
        $this->tags = self::_num2str($tags);
        return $this;
    }

    /**
     * @param null $expire
     * @return CacheKey
     */
    public function expire($expire) {
        $this->expire = $expire;
        return $this;
    }

    /**
     * 获取key
     *
     * @return array
     */
    public function getKey() {
        $key = [];

        if (!empty($this->moduleName)) {
            $key[] = $this->moduleName;
        } else {
            $key[] = request()->module();
        }

        if (!empty($this->resourceType)) {
            $key[] = $this->resourceType;
        } else {
            $key[] = "";
        }

        if (!empty($this->tags)) {
            $key[] = md5(join(',', $this->tags));
        }

        $key = join(".", $key);
        return $key;
    }

    /**
     * 获取缓存key对应的内容
     *
     * @return mixed
     */
    public function getValue() {
        $key = $this->getKey();
        return Cache::get($key);
    }

    /**
     * 设置缓存key对应的内容
     *
     * @param $value
     * @param null $expire
     */
    public function setValue($value, $expire = null) {
        $key = $this->getKey();
        if (empty($expire)) {
            $expire = $this->expire;
        }
        Db::name("CacheKey")->insertGetId([
            "module_name" => $this->moduleName,
            "key" => $key,
            "expire" => $expire ? (time() + $expire) : $expire,
            "type" => $this->resourceType,
            "tags" => json_encode($this->tags)
        ], true);
        Cache::set($key, $value, $expire);
    }

    /**
     * 删除缓存
     *
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function deleteValue() {
        $key = $this->getKey();
        Cache::rm($key);
        Db::name("CacheKey")->where([
            'key' => $key
        ])->delete();
    }

    /**
     * 清除失效的key
     *
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public static function clearExpiredKey() {
        Db::name("CacheKey")->where("expire is not null and expire < " . time())->delete();
    }

    /**
     * 缓存失效
     *
     * @param $resourceType
     * @param bool|array $tags
     * @param $moduleName
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function remove($resourceType, $tags = false, $moduleName = false) {
        self::clearExpiredKey();

        $query = Db::name("CacheKey");
        $deleteQuery = Db::name("CacheKey");
        if (!empty($resourceType)) {
            $query->where("type", $resourceType);
            $deleteQuery->where("type", $resourceType);
        }
        if (!empty($tags)) {
            foreach ($tags as $name => $value) {
                $query->where("tags", "like", '%"' . $name . '":"' . $value . '"%');
                $deleteQuery->where("tags", "like", '%"' . $name . '":"' . $value . '"%');
            }
        }
        if (!empty($moduleName)) {
            $query->where("module_name", $moduleName);
            $deleteQuery->where("module_name", $moduleName);
        }
        $cacheKeys = $query->select();
        foreach ($cacheKeys as $cacheKey) {
            Cache::rm($cacheKey['key']);
        }
        $deleteQuery->delete();
    }


    /**
     * 将变量中的所有数字转换为字符串
     *
     * @param $instance
     * @return array|string
     */
    private static function _num2str($instance) {
        if (is_string($instance)) {
            return $instance;
        }
        if (is_numeric($instance)) {
            return strval($instance);
        }
        if (is_array($instance) || is_object($instance)) {
            $newInstance = [];
            foreach ($instance as $key => $value) {
                $key = self::_num2str($key);
                $value = self::_num2str($value);
                $newInstance[$key] = $value;
            }
            return $newInstance;
        }
        return strval($instance);
    }
}